home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Mac-Source 1994 July
/
Mac-Source_July_1994.iso
/
C and C++
/
Libraries
/
GUSI
/
GUSIFSp.cp
< prev
next >
Wrap
Text File
|
1993-11-16
|
16KB
|
785 lines
/*********************************************************************
Project : GUSI - Grand Unified Socket Interface
File : GUSIFSp.cp - Dealing with paths
Author : Matthias Neeracher <neeri@iis.ethz.ch>
Started : 15Jun92 Language : MPW C++
06Sep92 MN Clear ioACUser
12Sep92 MN Renamed Paths.h to GUSIFSp_P.h
15Nov92 MN Forgot a few consts
15Nov92 MN Rename GUSIFSp_P.h to TFileSpec.h (there we go again)
15Jan93 MN IsParentOf
06Feb93 MN Use FSMakeFSSpec if possible
01Mar93 MN Bless
21Jun93 MN Throw out the inline
17Jul93 MN LastInfo
27Sep93 MN FSpSmartMove
24Oct93 MN Allow changing case in a rename
Last : 24Oct93
*********************************************************************/
#include "GUSI_P.h"
#include "TFileSpec.h"
#include <Errors.h>
#include <Memory.h>
#include <Aliases.h>
#include <string.h>
#include <ioctl.h>
#include <fcntl.h>
#include <errno.h>
#include <TextUtils.h>
OSErr TFileSpec::error;
short TFileSpec::curVol;
long TFileSpec::curDir = -1;
CInfoPBRec TFileSpec::lastInfo;
OSErr TFileSpec::ChDir(const TFileSpec & spec)
{
TFileSpec nudir(spec);
nudir += "\p";
if (error)
return error;
curVol = nudir.vRefNum;
curDir = nudir.parID;
return noErr;
}
static OSErr CurrentDir(short & vRefNum, long & parID)
{
OSErr error;
WDPBRec vol;
Str63 name;
vol.ioNamePtr = name;
if (error = PBHGetVolSync(&vol))
return error;
vRefNum = vol.ioWDVRefNum;
parID = vol.ioWDDirID;
return noErr;
}
OSErr TFileSpec::DefaultDir()
{
if (curDir != -1) {
vRefNum = curVol;
parID = curDir;
return noErr;
} else
return error = CurrentDir(vRefNum, parID);
}
OSErr TFileSpec::Default()
{
if (!DefaultDir())
--*this;
return error;
}
TFileSpec::TFileSpec(const FSSpec & spec, Boolean useAlias)
: FSSpec(spec)
{
if (!useAlias && hasAlias)
Resolve();
}
TFileSpec::TFileSpec(short vRefNum, long parID, ConstStr31Param name, Boolean useAlias)
{
if (!hasMakeFSSpec || FSMakeFSSpec(vRefNum, parID, name, this)) {
this->vRefNum = vRefNum;
this->parID = parID;
memcpy(this->name, name, *name+1);
}
if (!useAlias && hasAlias)
Resolve();
}
TFileSpec::TFileSpec(short wd, ConstStr31Param name, Boolean useAlias)
{
if (!hasMakeFSSpec || FSMakeFSSpec(wd, 0, name, this)) {
WDPBRec wdPB;
wdPB.ioNamePtr = nil;
wdPB.ioVRefNum = wd;
wdPB.ioWDIndex = 0;
wdPB.ioWDProcID = 0;
/* Change the Working Directory number in vRefnum into a real vRefnum */
/* and DirID. The real vRefnum is returned in ioVRefnum, and the real */
/* DirID is returned in ioWDDirID. */
if (error = PBGetWDInfoSync(&wdPB))
return;
vRefNum = wdPB.ioWDVRefNum;
parID = wdPB.ioWDDirID;
memcpy(this->name, name, *name+1);
}
if (!useAlias && hasAlias)
Resolve();
}
TFileSpec::TFileSpec(OSType object, short vol, long dir)
{
if (object == kTempFileType && dir) {
vRefNum = vol;
parID = dir;
} else if (
error =
FindFolder(
vol, (object == kTempFileType) ? kTemporaryFolderType : object,
true, &vRefNum, &parID)
)
return;
if (object == kTempFileType) {
static long nr = -1;
strcpy((char *) name, (char *) "\ptmp00000");
do {
nr = (nr + 1) % 100000;
sprintf((char *) name+4, "%05ld", nr);
} while (Exists());
} else {
*this -= 1;
}
}
void TFileSpec::Bless()
{
if (hasMakeFSSpec) {
FSSpec spec = *this; // Dont know what happens to an aliased name
error = FSMakeFSSpec(spec.vRefNum, spec.parID, spec.name, this);
} else
error = noErr;
}
#define maxPathLen 512
static char fullPath[maxPathLen];
/* Convert an FSSpec into a full pathname. The pathname is accumulated on the
high end of path to avoid excessive copying.
*/
char * TFileSpec::FullPath() const
{
char * curPath;
/* Special case: a volume was specified */
if (parID == fsRtParID) {
memcpy(fullPath, name+1, *name);
curPath = fullPath+*name;
curPath[0] = ':';
curPath[1] = 0;
error = noErr;
return fullPath;
}
fullPath[maxPathLen-1] = 0;
curPath = fullPath+maxPathLen-*name-1;
memcpy(curPath, name+1, *name);
lastInfo.dirInfo.ioNamePtr = (StringPtr) fullPath;
lastInfo.dirInfo.ioDrParID = parID;
do {
lastInfo.dirInfo.ioVRefNum = vRefNum;
lastInfo.dirInfo.ioFDirIndex = -1;
lastInfo.dirInfo.ioDrDirID = lastInfo.dirInfo.ioDrParID;
if (error = PBGetCatInfoSync(&lastInfo))
return "";
*--curPath = ':';
curPath -= *fullPath;
memmove(curPath, fullPath+1, *fullPath);
} while (lastInfo.dirInfo.ioDrDirID != fsRtDirID);
return curPath;
}
char * TFileSpec::RelPath() const
{
short curVRef;
long curDirID;
char * curPath;
if (CurrentDir(curVRef, curDirID))
return FullPath();
/* Special case: a volume was specified */
if (parID == fsRtParID) {
if (vRefNum == curVRef && curDirID == fsRtDirID)
curPath = fullPath;
else {
memcpy(fullPath, name+1, *name);
curPath = fullPath+*name;
}
curPath[0] = ':';
curPath[1] = 0;
return fullPath;
}
lastInfo.dirInfo.ioNamePtr = (StringPtr)fullPath;
lastInfo.dirInfo.ioVRefNum = curVRef;
lastInfo.dirInfo.ioFDirIndex = -1;
lastInfo.dirInfo.ioDrDirID = curDirID;
if (error = PBGetCatInfoSync(&lastInfo))
return "";
if (curVRef == vRefNum
&& lastInfo.dirInfo.ioDrParID == parID
&& !memcmp (fullPath, name, *fullPath+1)
) {
fullPath[0] = ':';
fullPath[1] = 0;
return fullPath;
}
fullPath[maxPathLen-1] = 0;
curPath = fullPath+maxPathLen-*name-1;
memcpy(curPath, name+1, *name);
lastInfo.dirInfo.ioNamePtr = (StringPtr) fullPath;
lastInfo.dirInfo.ioDrParID = parID;
do {
*--curPath = ':';
/* Test fur current directory */
if (curVRef == vRefNum && curDirID == lastInfo.dirInfo.ioDrParID)
return strchr(curPath+1, ':') ? curPath : curPath+1;
lastInfo.dirInfo.ioVRefNum = vRefNum;
lastInfo.dirInfo.ioFDirIndex = -1;
lastInfo.dirInfo.ioDrDirID = lastInfo.dirInfo.ioDrParID;
if (error = PBGetCatInfoSync(&lastInfo))
return "";
curPath -= *fullPath;
memmove(curPath, fullPath+1, *fullPath);
} while (lastInfo.dirInfo.ioDrDirID != fsRtDirID);
return curPath;
}
OSErr TFileSpec::CatInfo(CInfoPBRec & info, Boolean dirInfo) const
{
info.dirInfo.ioVRefNum = vRefNum;
info.dirInfo.ioDrDirID = parID;
info.dirInfo.ioNamePtr = name;
info.dirInfo.ioFDirIndex = dirInfo ? -1 : 0;
#ifdef OnceThisFieldIsDefined
info.dirInfo.ioACUser = 0;
#else
info.dirInfo.filler2 = 0;
#endif
return error = PBGetCatInfoSync(&info);
}
TFileSpec TFileSpec::operator--()
{
CatInfo(lastInfo, true);
if (!error)
parID = lastInfo.dirInfo.ioDrParID;
return *this;
}
TFileSpec TFileSpec::operator-=(int levels)
{
while (levels-- > 0) {
--*this;
if (this->Error())
break;
}
return *this;
}
TFileSpec TFileSpec::operator-(int levels) const
{
TFileSpec spec = *this;
return spec -= levels;
}
OSErr TFileSpec::Resolve(const CInfoPBRec & info)
{
Boolean isFolder;
Boolean wasAlias;
return error =
(hasAlias && IsAlias(info)) ?
ResolveAliasFile(this, true, &isFolder, &wasAlias) :
noErr;
}
OSErr TFileSpec::Resolve(Boolean gently)
{
CatInfo(lastInfo);
if (error)
if (gently)
return error = noErr;
else
return error;
else
return Resolve(lastInfo);
}
Boolean TFileSpec::Exists() const
{
Boolean res;
res = !CatInfo(lastInfo);
error = noErr;
return res;
}
Boolean TFileSpec::operator==(const TFileSpec & other) const
{
return vRefNum == other.vRefNum
&& parID == other.parID
&& EqualString(name, other.name, false, true);
}
Boolean TFileSpec::operator!=(const TFileSpec & other) const
{
return vRefNum != other.vRefNum
|| parID != other.parID
|| !EqualString(name, other.name, false, true);
}
Boolean TFileSpec::IsParentOf(const TFileSpec & other) const
{
for (TFileSpec oth = other - 1; !oth.Error() && *this != oth; --oth);
return !oth.Error();
}
TFileSpec TFileSpec::operator+=(ConstStr31Param name)
{
if (*name > 63)
return bdNamErr;
if (CatInfo(lastInfo))
goto punt;
// Resolve if an alias
if (IsAlias(lastInfo))
if (Resolve(lastInfo) || CatInfo(lastInfo))
goto punt;
if (IsFile(lastInfo)) {
error = bdNamErr;
goto punt;
}
parID = lastInfo.dirInfo.ioDrDirID;
memcpy(this->name, name, *name+1);
punt:
return *this;
}
TFileSpec TFileSpec::operator+(ConstStr31Param name) const
{
TFileSpec spec = *this;
return spec += name;
}
TFileSpec TFileSpec::operator+=(const char * name)
{
int len = strlen(name);
if (len > 63)
return bdNamErr;
if (CatInfo(lastInfo))
goto punt;
// Resolve if an alias
if (IsAlias(lastInfo))
if (Resolve(lastInfo) || CatInfo(lastInfo))
goto punt;
if (IsFile(lastInfo)) {
error = bdNamErr;
goto punt;
}
parID = lastInfo.dirInfo.ioDrDirID;
memcpy(this->name+1, name, *this->name = len);
punt:
return *this;
}
TFileSpec TFileSpec::operator+(const char * name) const
{
TFileSpec spec = *this;
return spec += name;
}
TFileSpec TFileSpec::operator[](short index) const
{
TFileSpec spec = *this;
lastInfo.dirInfo.ioVRefNum = spec.vRefNum;
lastInfo.dirInfo.ioDrDirID = spec.parID;
lastInfo.dirInfo.ioNamePtr = spec.name;
lastInfo.dirInfo.ioFDirIndex = index;
error = PBGetCatInfoSync(&lastInfo);
return spec;
}
TFileSpec::TFileSpec(const char * path, Boolean useAlias)
{
int pathLen = strlen(path);
StringPtr name = (StringPtr) fullPath;
char * nextPath;
if (hasMakeFSSpec) {
DefaultDir();
nextPath = (char *) memccpy((char *) name + 1, path, 0, 254);
if (nextPath)
name[0] = nextPath - (char *) name - 2;
else
name[0] = 254;
switch (error = FSMakeFSSpec(vRefNum, parID, name, this)) {
case fnfErr:
error = noErr;
// Fall through:
case noErr:
goto done; // Going down slow ain't the only way to go
default:
break;
}
}
if (path[0] == ':' || !(nextPath = strchr(path, ':'))) {
Default();
if (*path == ':')
++path;
} else {
ParamBlockRec vol;
if (nextPath - (char *) path > 62) {
error = bdNamErr;
return;
}
memcpy(name+1, (char *) path, *name = nextPath - (char *) path + 1);
vol.volumeParam.ioNamePtr = name;
vol.volumeParam.ioVolIndex = -1;
if (error = PBGetVInfoSync(&vol))
return;
vRefNum = vol.volumeParam.ioVRefNum;
parID = fsRtDirID;
path = nextPath + 1;
--*this;
}
if (error)
return;
while (*path) {
if (*path == ':') {
--*this;
++path;
if (error)
return;
else
continue;
}
if (nextPath = strchr(path, ':'))
*nextPath = 0;
*this += path;
if (error)
return;
if (nextPath) {
*nextPath = ':';
path = nextPath + 1;
} else
break;
}
done:
if (!useAlias && hasAlias)
Resolve();
}
/* Convert a FSSpec into a full pathname. */
char * FSp2FullPath(const FSSpec * desc)
{
TFileSpec spec(*desc);
return spec.FullPath();
}
/* Convert a FSSpec into a relative pathname. */
char * FSp2RelPath(const FSSpec * desc)
{
TFileSpec spec(*desc);
return spec.RelPath();
}
/* Convert a working directory & file name into a FSSpec. */
OSErr WD2FSSpec(short wd, ConstStr31Param name, FSSpec * desc)
{
TFileSpec spec(wd, name);
*desc = spec;
return spec.Error();
}
/* Convert a pathname into a file spec. */
OSErr Path2FSSpec(const char * path, FSSpec * desc)
{
TFileSpec spec(path);
*desc = spec;
return spec.Error();
}
/* Convert a working directory & file name into a FSSpec. */
OSErr Special2FSSpec(OSType object, short vol, long dirID, FSSpec * desc)
{
TFileSpec spec(object, vol, dirID);
*desc = spec;
return spec.Error();
}
/* Return FSSpec of (vRefNum, parID) */
OSErr FSpUp(FSSpec * desc)
{
TFileSpec spec(*desc);
*desc = --spec;
return spec.Error();
}
/* Return FSSpec of file in directory denoted by desc */
OSErr FSpDown(FSSpec * desc, ConstStr31Param name)
{
TFileSpec spec(*desc);
*desc = spec + name;
return spec.Error();
}
/* Call GetCatInfo for file system object. */
OSErr FSpCatInfo(const FSSpec * desc, CInfoPBRec * info)
{
TFileSpec spec(*desc);
return spec.CatInfo(*info);
}
/* Return FSSpec of nth file in directory denoted by (vRefNum, parID) */
OSErr FSpIndex(FSSpec * desc, short n)
{
TFileSpec spec(*desc);
*desc = spec[n];
return spec.Error();
}
static OSErr DefaultVRef(short & vRef)
{
OSErr err;
ParamBlockRec vol;
vol.volumeParam.ioNamePtr = nil;
if (err = PBGetVolSync(&vol))
return err;
vRef = vol.volumeParam.ioVRefNum;
return noErr;
}
OSErr FSpSmartMove(const FSSpec * from, const FSSpec * to)
{
OSErr err;
TFileSpec fromspec(*from);
TFileSpec tospec(*to);
TFileSpec toparent = tospec - 1;
TFileSpec corner;
CInfoPBRec info;
if (!fromspec.vRefNum)
if (err = DefaultVRef(fromspec.vRefNum))
return err;
if (!tospec.vRefNum)
if (err = DefaultVRef(tospec.vRefNum))
return err;
if (fromspec.vRefNum != tospec.vRefNum)
return badMovErr;
Boolean diffname = !EqualString(fromspec.name, tospec.name, false, true);
Boolean diffdir = fromspec.parID != tospec.parID;
Boolean toexists = !tospec.CatInfo(info);
TFileSpec tmpto;
if (!diffname && !diffdir) { /* Files are identical, except possibly for case */
err = noErr;
goto cleanupcase;
}
if (err = fromspec.CatInfo(info))
return err;
if (!IsFile(info) && fromspec.IsParentOf(tospec))
return badMovErr;
if (toexists)
if (!IsFile(info) && info.dirInfo.ioDrNmFls)
return fBsyErr;
else {
tmpto = TFileSpec(kTempFileType, tospec.vRefNum, tospec.parID);
if (err = HRename(tospec.vRefNum, tospec.parID, tospec.name, tmpto.name))
return err;
}
if (!diffdir) {
err = HRename(fromspec.vRefNum, fromspec.parID, fromspec.name, tospec.name);
goto cleanuptmp;
} else if (!diffname) {
err =
CatMove(
fromspec.vRefNum, fromspec.parID, fromspec.name,
toparent.parID, toparent.name);
goto cleanuptmp;
}
corner = TFileSpec(fromspec.vRefNum, fromspec.parID, tospec.name);
if (!corner.Exists()) {
err = HRename(fromspec.vRefNum, fromspec.parID, fromspec.name, tospec.name);
if (!err)
if (err =
CatMove(
fromspec.vRefNum, fromspec.parID, tospec.name,
toparent.parID, toparent.name)
)
HRename(fromspec.vRefNum, fromspec.parID, tospec.name, fromspec.name);
goto cleanuptmp;
}
{
TFileSpec secondcorner(kTempFileType, tospec.vRefNum, tospec.parID);
memcpy(corner.name, secondcorner.name, secondcorner.name[0]+1);
while (corner.Exists() || secondcorner.Exists()) {
TFileSpec newcorner(kTempFileType, secondcorner.vRefNum, secondcorner.parID);
memcpy(corner.name, newcorner.name, newcorner.name[0]+1);
memcpy(secondcorner.name, newcorner.name, newcorner.name[0]+1);
}
}
err = HRename(fromspec.vRefNum, fromspec.parID, fromspec.name, corner.name);
if (!err)
if (err =
CatMove(
fromspec.vRefNum, fromspec.parID, corner.name,
toparent.parID, toparent.name)
)
HRename(fromspec.vRefNum, fromspec.parID, corner.name, fromspec.name);
else if (err =
HRename(tospec.vRefNum, tospec.parID, corner.name, tospec.name)
) {
TFileSpec fromparent = fromspec - 1;
CatMove(
tospec.vRefNum, tospec.parID, corner.name,
fromparent.parID, fromparent.name);
HRename(fromspec.vRefNum, fromspec.parID, corner.name, fromspec.name);
}
cleanuptmp:
if (toexists)
if (err)
HRename(tmpto.vRefNum, tmpto.parID, tmpto.name, tospec.name);
else
HDelete(tmpto.vRefNum, tmpto.parID, tmpto.name);
cleanupcase:
if (!err && !diffname)
return HRename(tospec.vRefNum, tospec.parID, tospec.name, tospec.name);
else
return err;
}